# coding: utf-8
import ujson
import requests
import threading
from setting import app_cof
from requests import Response
from typing import Any, Literal
from .log_handle import logger
from .base_utils import dictToUriStr


class RequestHandle:
    """接口请求封装"""
    _instance: dict = {}
    lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if cls._instance :
            return cls._instance
        with cls.lock:
            if not cls.__instance:
                cls.__instance = super().__new__(cls)
        return cls.__instance

    def visited(self, method: str, url: str, **kwargs) -> Response:
        return requests.request(method=method.upper(), url=url, **kwargs)

    @staticmethod
    def required(method, url, data=None, headers=None):
        """application为表单格式"""
        res = ""
        if method == "get":
            res = requests.get(url=url, params=data, headers=headers)
        if method == "post":
            res = requests.post(url=url, data=data, headers=headers)
        if method == "put":
            res = requests.put(url=url, data=data, headers=headers)
        if method == "delete":
            res = requests.put(url=url, params=data, headers=headers)
        if method == "patch":
            res = requests.put(url=url, data=data, headers=headers)
        return res

    @staticmethod
    def required_json(method, url, data=None, headers=None):
        """application为json格式"""
        res = ""
        if method == "get":
            res = requests.get(url=url, params=data)
        if method == "post":
            res = requests.post(url=url, json=data, headers=headers)
        if method == "put":
            res = requests.put(url=url, json=data, headers=headers)
        if method == "delete":
            res = requests.put(url=url, params=data, headers=headers)
        if method == "patch":
            res = requests.put(url=url, json=data, headers=headers)
        return res

    def currency(
        self,
        _module: str,
        method: Literal["get", "post", "put", "patch", "delete"],
        point: str,
        content_type: str = "application/json;charset=UTF-8",
        resful: bool = True,
        **kwargs
    ) -> Any | Response:
        """
        Args:
            _module(str): request module
            method (str): request method
            point (str): request url
            content_type (str): request headers content type, default: json
            resful (bool): whether to serialize output
        """
        headers: dict = {
            "Content-Type": content_type,
            "Connection": "Keep-Alive",
            "Accept-Encoding": "gzip"
        }
        match _module:
            case "app":
                headers["access-token"] = self.db.get("AppToken")
                _url: str = app_cof.AppUrl + point
            case "center":
                headers["access-token"] = self.db.get("CenterToken")
                _url: str = app_cof.CenterUrl + point
            case "client":
                headers["access-token"] = self.db.get("ClientToken")
                _url: str = app_cof.ClientUrl + point
            case _:
                raise Exception("request module to be implemented!")
        params: dict = kwargs.get("params", {})

        # output request method and uri information
        logger.info("{}, {}".format(method, point + dictToUriStr(params)))

        res: Response = self.visited(method, _url, headers=headers, **kwargs)
        assert res.status_code in (200, 201, 204)
        if resful:
            return ujson.loads(str(res.content, encoding="utf-8"))
        return res
 
    def app_request_json(
        self,
        method: str,
        point: str,
        resful: bool = False,
        **kwargs
    ) -> Any | Response:
        """App App Request, Type: json"""
        return self.currency(
            _module="app",
            method=method,
            point=point,
            resful=resful,
            **kwargs
        )

    def app_request_xml(
        self,
        method: str,
        point: str,
        content_type: str = "text/xml;charset=utf-8",
        resful: bool = False,
        **kwargs
    ) -> Any | Response:
        """App App Request, Type: xml"""
        return self.currency(
            _module="app",
            method=method,
            point=point,
            content_type=content_type,
            resful=resful,
            **kwargs
        )

    def center_request_json(
        self,
        method: str,
        point: str,
        resful: bool = True,
        **kwargs
    ) -> Any | Response:
        """Center App Request, Type: json"""
        return self.currency(
            _module="center",
            method=method,
            point=point,
            resful=resful,
            **kwargs
        )
    ...
